home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SuperHack
/
SuperHack CD.bin
/
CODING
/
CPP
/
WATFAQ.ZIP
/
WATFAQ.TXT
Wrap
Text File
|
1997-01-10
|
102KB
|
2,157 lines
The WATCOM C/C++ Programmer's FAQ
WW WW AA TTTTTTTT CCCC OOOO MM MM cccc /
WW WW AAAA TT CC CC OO OO MMMMMMMM cc /
WW WW AA AA TT CC OO OO MM MMMM MM cccc /
WW WW AA AA TT CC OO OO MM MM MM /
WW WW WW AA AA TT CC OO OO MM MM MM /
WW WWWW WW AAAAAAAA TT CC OO OO MM MM MM / cccc + +
WWWWWWWW AA AA TT CC CC OO OO MM MM MM cc +++ +++
WW WW AA AA TT CCCC OOOO MM MM MM cccc + +
Programmer's
FFFFFFFFFFFFFFFFFF AAAAA QQQQQQQQQQQQQQ
FFFFFFFFFFFFFFFFFF AAAAAAA QQQQQQQ QQQQQQ
FFFFFF AAAAAAAAA QQQQQQ QQQQQQ
FFFFFF AAAAAAAAAAA QQQQQQQ QQQQQQ
FFFFFFFFFFFFFF AAAAAA AAAAAA QQQQQQQ QQQQQQQ
FFFFFFFFFFFFFF AAAAAA AAAAAA QQQQQQQ QQQQQQQ
FFFFFF AAAAAA AAAAAA QQQQQQQ QQQ QQQQQQQ
FFFFFF AAAAAAAAAAAAAAAAAAA QQQQQQQ QQQQQQQQQQQ
FFFFFF AAAAAAAAAAAAAAAAAAAAA QQQQQQQQQQQQQQQQQQQ
FFFFFF AAAAAA AAAAAA QQQQQQQQQQQQQQQQQQQQ
QQQQQQQQQQ
Written by Paul Hsieh
qed@chromatic.com
Revision 2.8
August 4, 1996
(c) Copyright 1996, Paul Hsieh. All Rights Reserved.
This document may be freely distributed in any format desired so long as
the contents are not modified beyond non-obtrusive formatting.
Please note that although I've made a reasonable effort to verify the
material contained in this FAQ, I make no guarrantees. The things written
here are as true as I know them to be and should not be interpreted as
anything more. None of WATCOM, PowerSoft/Sybase or TenBerry systems or
any other relevant company has officially endorsed this FAQ. Furthermore,
I have no affiliation with WATCOM, PowerSoft/Sybase or TenBerry systems.
WATCOM, PowerSoft, Sybase, TenBerry Systems, QNX, IBM, OS/2, Microsoft,
Windows, Win32, Direct Draw, Direct X, Intel, Intel's RDX, Metaware,
Symantec, Borland, CauseWay, Fastgraph, Varmint's Audio Tools, YackIcons,
WordUp Graphics Toolkit, PC Magazine, Soft ICE, Phar lap, PModeW, Team 17
etc., are copyrights/trademarks of their respective owners.
----------------------------------------------------------------------------
Introduction
Many/most of the questions dealt with here assume that you already own a
version of the WATCOM C/C++ compiler. Ordering information is available
on WATCOM's world wide web site.
As my personal strengths are in DOS coding, I have slanted this FAQ at
DOS programming using WATCOM C/C++. If you are willing to contribute
information regarding Windows, OS/2 programming or QNX programming please
send it to me and I will include it. Please note that I will only be able
to easily verify DOS information (and Windows information, only with great
difficulty.)
This FAQ mixes advocation with technical information. It has been written
this way because after years of posting on USENET this has become my
natural style of writing.
----------------------------------------------------------------------------
Frequently asked Questions
~~~~~~~~~~~~~~~~~~~~~~~~~~
These are very commonly asked questions that people ask about WATCOM C/C++.
Q01. What is WATCOM C/C++? What does WATCOM C/C++ come with?
Q02. Where are WATCOM C/C++'s related web/ftp sites?
Q03. Why is WATCOM C/C++ so popular?
Q04. What's the syntax for ____? How do I use the ____ tool? How do I
make the code generator do ____? I just don't get it.
Q05. I think there is a bug in the compiler, what should I do?
Q06. Why do so many games use the DOS4GW.EXE DOS extender?
Q07. What libraries are available for WATCOM C/C++?
Q08. How do I program for Direct X using WATCOM C/C++?
Q09. How do I program for Intel's RDX using WATCOM C/C++?
Q10. Is the code WATCOM C/C++ produces the fastest/tightest?
Q11. How do I use WATCOM's tools to help me optimize my code?
Q12. How does WATCOM C/C++ compare with other C compilers?
Q13. How do I debug DOS4GW apps under Windows 95?
Q14. How do I debug WATCOM apps using Soft-ICE?
Q15. How do I enable virtual memory for my DOS4GW application? How do I
know exactly what interrupts dos4gw handles all by itself? How do I
know exactly what a programmer have to do, using dos interrupts from
protected mode?
Q16. Why doesn't WATCOM use "_asm" for inline assembly like Microsoft and
Borland? Afterall isn't that standard?
Q17. Why does my code work only when I compile with debugging info on?
Q18. What is FLAT memory model? What is the advantage of a 32 bit
compiler such as WATCOM C/C++ over 16 bit compilers? What are the
differences? Will I be able to move my 16 bit DOS code straight over
to 32 bit?
Q19. I am getting this weird error message ...
Q20. I am having malloc troubles. It seems that I am trashing the heap
but I don't know how to debug it.
Q21. How do I write directly to graphics memory?
Q22. How do I install a mouse event handler?
Q23. What is DPMI and what role does it play in using WATCOM C/C++? How
do I communicate between the 16 bit world and 32 bit world on my PC?
Q24. What if I really need to compile a 16 bit model program?
Q25. Why do WATCOM's results and Visual C++'s results differ on the same
source code? Why does WATCOM implement the default signedness of
chars different from everyone else? I am having difficulty porting
code to WATCOM C/C++.
Q26. Can I link external assembly files together with my C files?
Q27. How do #pragma's work? How do I do inline assembly language?
Q28. How do I do compiled bitmaps? How do I do on-the-fly generated
code?
Q29. How do I install a 32 bit interrupt vector? How do I install a
bimodal interrupt?
Q30. How do I get rid of the DOS4GW banner? How do I bind DOS4GW.EXE to
my application? How do I get rid of the external DOS4GW.EXE
altogether? What other DOS extenders can I use?
Q31. How do I make WATCOM C/C++ work with the latest OS/2 Toolkit?
Q32. Are there any other WATCOM C/C++ caveats?
Q33. Will WATCOM C/C++ support MMX?
Q34. So what is your story? Why did you do this?
Cool contributions
~~~~~~~~~~~~~~~~~~
These are contributions sent to me that do not correspond to a frequently
asked question such as above, but which nevertheless are worth including.
C01. Profiling and debugging all rolled into one using an external
terminal connected by serial. Contributed by Charlie Wallace.
C02. Convert WATCOM's help file format to a text file for easier
reading and potentially for easier manipulation.
----------------------------------------------------------------------------
Questions with answers
~~~~~~~~~~~~~~~~~~~~~~
Q01. What is WATCOM C/C++? What does WATCOM C/C++ come with?
A01. WATCOM C/C++ is an Intel x86 based ANSI C++ and C compiler. It
supports various target operating systems. Its most notable and exercised
strength is its 32 bit DOS based support. WATCOM has established its
reputation as the makers of a world leading C compiler and has been in
business for about 10 years. You can get a more complete description of
the compiler on the WATCOM web site, however here are the most notable
things that are included:
- 32 and 16 bit compilers, with standard libraries and DOS4GW.EXE.
- Additional DOS graphics and x86 specific libraries.
- Library manager and linker.
- All flavours of Windows programming including 16 and 32 bit MFC support
as well as Win32. (Includes Windows SDK help.)
- Numerous Windows development tools (dialogue editors and so on.)
- Support for Dos extenders, OS/2, QNX, AutoCAD and Novell NLMs.
- IDE: Editor, Debugger, Execution Sampler/Profiler, Make, Touch.
- Online documentation and sample code.
----------------------------------------------------------------------------
Q02. Where are WATCOM C/C++'s related web/ftp sites?
A02. These are the URLs that I am aware of:
WATCOM's home page
http://www.powersoft.com/products/languages/watccpl.html
WATCOM C/C++ readmes
ftp://ftp.powersoft.com/pub/c_cpp/maintfls
WATCOM C/C++ goodies
http://www.powersoft.com/services/files/c_gen.html
KNUT's WATCOM C/C++ tutorial
http://www.oslonett.no/home/oruud/wat_tut.htm
X2FTP site:
ftp://x2ftp.oulu.fi/pub/msdos/programming/watcom
Official site for the WATCOM C/C++ FAQ
http://www.geocities.com/SiliconValley/9498/watfaq.txt
FTP site for downloading the WATCOM C/C++ FAQ
ftp://x2ftp.oulu.fi/pub/msdos/programming/watcom/watfaq21.zip
Previous WATCOM C/C++ FAQ
ftp://x2ftp.oulu.fi/pub/msdos/programming/watcom/watcom.07
Miscellaneous WATCOM C/C++ and OS/2 device driver notes
http://www.wdi.co.uk/os2dd/QA__0009.htm
Email List server for WATCOM users
WATCOM-L@umdd.umd.edu
send a message to listserv@umdd.umd.edu with the first line
of your message containing:
"SUBSCRIBE WATCOM-L John Doe" to subscribe.
USENET Newsgroups
news:alt.msdos.programmer
news:comp.os.msdos.programmer
news:rec.games.programmer
For tutorials on C/C++ (not specifically WATCOM) I have the following URLs:
C tutorials
http://www.strath.ac.uk/CC/Courses/NewCcourse/ccourse.html
http://www.iftech.com/classes/c/c0.htm
ftp://x2ftp.oulu.fi/pub/msdos/programming/docs/teach-c.zip
C++ tutorial
http://www.iftech.com/classes/cpp/cpp0.htm
----------------------------------------------------------------------------
Q03. Why is WATCOM C/C++ so popular?
A03. WATCOM C/C++ is a very good tool. It was the first pure 32 bit C/C++
compiler widely available for x86 platforms. It is a cross platform, high
performance object code generator with no shortage of support tools. It
is on these merits that WATCOM has sustained its popularity.
Somewhere around 1992-93, WATCOM decided to drop the price (to a mere $400
Cdn vs. the old price of $1200 US) and started advertising more heavily in
magazines such as BYTE and PC Magazine. Around this time I was heavily
advocating it (version 9.0) it in newsgroups such as "rec.games.programmer"
as the premiere C compiler for high performance and reliability, making such
bold statements as: "WATCOM C/C++ will produce code which is at *least*
twice as fast as your current 16 bit compiler, and more typically around
five times as fast" which was not stretching the truth as far as I knew it.
Flame wars ensued where the focus was not only Borland and Microsoft, but
WATCOM.
Then a single program was introduced that brought immediate and serious
attention to this compiler: DOOM. What is this magical "DOS4GW" thing that
makes DOOM so good? Were the DOOM programmers serious when they said they
used almost no assembly language? What C compiler could they have possibly
used that could pump that much game onto the screen? Soon, more and more
games were made, hailing the telltale "DOS4GW" banner. A few years later
PC Magazine ran a comparative study of a collection of C compilers. They
hailed WATCOM C/C++ v9.5 for producing the fastest code (by a *wide* margin)
but criticized it for its klunky command line driven interface.
Since then, many game companies switched and dozens of titles appeared
with the "DOS4GW" banner displayed proudly including: Raptor, System
Shock, Descent, Magic Carpet, NASCAR Racing, Terminal Velocity etc. 32
bit was finally becoming a reality on the PC, and it had nothing to do
with "Windows" or "OS/2". But even IBM was getting smart. Numerous OS/2
utilities and parts of the OS itself were compiled using WATCOM C/C++.
With version 10.0 WATCOM introduced an IDE, added support for MFC and
added an assembler. With 10.5 they decided to out source the new and
improved IDE to an award winning third party developer, included better
support for Win 95 and have built in a higher degree of Visual C++
compatability. With its licensing of MFC and ability to do ... well just
about anything, WATCOM has clearly set its sights on one goal: To become
the defacto standard C/C++ compiler for PCs. Even Microsoft dares not
ignore WATCOM C/C++; "Direct X" is compatible with WATCOM C/C++ (this was
no doubt at the demand of the 3rd party BETA testers.)
----------------------------------------------------------------------------
Q04. What's the syntax for ____? How do I use the ____ tool? How do I
make the code generator do ____? I just don't get it.
A04. The first place to look when trying to deal with general questions
is the online help. In a DOS box you can access the help via:
WHELP help_file [topic_name]
If you've installed the compiler to use the CDROM, be sure to have the
WATCOM CDROM in the CDROM drive. It takes a little digging but there is a
lot of online information available.
If you give no parameters, most of the tools will respond with proper
command line syntax.
Additionally, the file %WATCOM%\DOS4GW.DOC gives you information on
configuring DOS4GW.EXE for certain systems and for using virtual memory
under DOS.
Remember, that the WATCOM C/C++ compiler was not designed with beginners
in mind. If you are just starting to learn C/C++ then I is suggest you
get plenty of reading on C/C++ in general and OS-specific programming
manuals (I.e., DOS, Windows, OS/2, QNX, or whatever target platform you
are interested in building for).
For a deeper understanding of WATCOM C/C++ you'll need to learn at least
bits and piece what object files, libraries, dll's, makefiles, and
protected mode are. Experienced programmers find that WATCOM C/C++
doesn't have any real brick walls that other compilers have, but that
coaxing it to do what you want it to do often takes some patience and
perseverence. That is the issue this FAQ is trying to address.
In general your pursuit of information when deal with difficulties using
the WATCOM C/C++ compilers should be in the order of: (1) Check the
online help files, (2) Check reference materials such as a DOS or Windows
programming books, as well as this FAQ, (3) Post a question to the
internet (including the USENET newsgroups, or the WATCOM listserver listed
above) (4) Contact WATCOM directly.
----------------------------------------------------------------------------
Q05. I think there is a bug in the compiler, what should I do?
A05. You'd be surprised by the number of "compiler bugs" people think
they've found. Stop. Take a deep breath and think about it for a moment.
The WATCOM C/C++ compiler is generally a very stable tool. Is your code
proper ANSI C? Are you violating the optimization assumptions assumed by
your choice of compiler switches? (Aliasing is the only one really at
issue.) Of the twenty or so "compiler bugs" that I thought I found, only
two of them were ever even close to being real compiler bugs (see "Q32.
Are there any other WATCOM C/C++ caveats?" Numbers 3 and 6.)
The fact that something works on one compiler but not another is not
necessarily an indication that one compiler is not functioning properly.
For example, another compiler may not buffer writes to stdout via printf.
So the fact that printf("Hello world"); echos immediately on one compiler
and not at all on another (WATCOM C/C++ buffer's writes, so indeed its an
example of a compiler that would not output anything) is not an indication
that one or the other compiler is broken.
In general, you are supposed to call them and ask them for assistance, but
these days, with their compiler being as popular as it is, it may be
difficult to get satisfactory responses from their customer support. You
may first try your luck on the newsgroups listed at the top of this FAQ,
if you have USENET access.
Powersoft/WATCOM themselves have set up a WWW bug report service on their
web page where you can submit problem reports. In general, if they think
your bug is nontrivial, then they will ask you to send them sample code
which isolates the problem. WATCOM provides a "shroud" utility that will
obfusticate your code if you are worried about unwanted distribution of
your sources. It is available at the following URL:
ftp://ftp.powersoft.com/pub/c_cpp/general/shroud.zip
However, I would highly recommend that if feasible, you simply duplicate
the problem in a clean project that does not expose any sources that you
don't want exposed.
Calling them for assistance should be a last resort, but if you feel that
you have found a genuine bug and have exhausted all reasonable avenues
then you should not hesitate to tell them about it. When and if they fix
the problem, the compiler will be a better tool for all of us.
When there are bugs in the compiler that WATCOM is aware of and have
fixed, they usually provide a patch that is available from their www and
ftp sites (listed above.)
----------------------------------------------------------------------------
Q06. Why do so many games use the DOS4GW.EXE DOS extender?
A06. DOS4GW.EXE is the royalty free redistributable 32 bit DOS extender
that comes with WATCOM C/C++. DOS4GW.EXE is made by "Tenberry Software"
(formerly Rational Systems) specifically for WATCOM. Although alternative
DOS extenders with more/different features exist, users of WATCOM C/C++
for DOS programming (that is to say, game programmers) will tend to use
DOS4GW by default. (It also has brand name recognition which may lead
some programmers to desire the telltale DOS4GW banner.)
----------------------------------------------------------------------------
Q07. What libraries are available for WATCOM C/C++?
A07. I don't have a comprehensive list, but I know that Varmint's Audio
Tools, Fast Graph, YackIcons, WordUp Graphics Toolkit, ZSVGA, Microsoft's
Direct X based Games SDK and Intel's RDX are notable libraries that come
in WATCOM C/C++ friendly flavors. In their latest versions, WATCOM has
really gone out of their way to make themselves more compatible with
Visual C++, which leads me to believe that many libraries out there which
have been compiled for Visual C++ will also work with WATCOM C/C++.
Needless to say there is no shortage of libraries out there that support
WATCOM C/C++. The WATCOM web site lists numerous 3rd party developers
that are supporting their C/C++ compiler.
Here's a list of some stuff available for WATCOM C/C++:
Graphics libraries
WGT Watcom ftp://x2ftp.oulu.fi/pub/msdos/programming/wgt51.zip
Xlib Watcom ftp://x2ftp.oulu.fi/pub/msdos/programming/xlib/xlib06p2.zip
Watcom ModeX ftp://x2ftp.oulu.fi/pub/msdos/programming/watcom/w_modex.zip
JLIB ftp://x2ftp.oulu.fi/pub/msdos/programming/djgpp2/jlib_1-5.zip
Intel's RDX http://www.intel.com/ial/rdx/
Zephyr's ZSVGA http://www.phoenix.net/~balkum/products/zpmsvga.html
gkit05b.zip ftp://x2ftp.oulu.fi/pub/msdos/programming/watcom/gkit05b.zip
3DGPL http://www.cs.mcgill.ca/~savs/3dgpl.html
Audio libraries
VAT Watcom ftp://x2ftp.oulu.fi/pub/msdos/programming/mxlibs/vatpm061.zip
SMIX Watcom ftp://x2ftp.oulu.fi/pub/msdos/programming/mxlibs/smixw125.zip
DSIK Watcom ftp://x2ftp.oulu.fi/pub/msdos/programming/mxlibs/dsik205.zip
----------------------------------------------------------------------------
Q08. How do I program for Direct X using WATCOM C/C++?
A08 I am not a Windows programming expert but the following information
appeared on the USENET:
>How well does the Games SDK work with Watcom? If well, how many
>trials did it take to get the 'magic options' set up right?
Works well, so far. I did have to use the windows.h file supplied with
the Games SDK, and that was hidden somewhere under the SAMPLES
subdirectory. I also had to define a couple of macros to get the samples
to compile. The whole thing took about 4 hours.
But then Ed Mueller said:
With 10.6, you no longer need to include windows.h supplied with the
Games SDK. The macros you need to define are NOIME and NOMCX.
And Marty (mmallick@watcom.on.ca; hey! An employee of WATCOM!) said:
In response to questions regarding the WATCOM C/C++ compiler and DirectX:
Watcom C/C++ 10.6 and DirectX 2.0
FYI:
The newly released DirectX 2.0 CD has a WATCOM directory that contains a
zip file that will make all of the necessary changes to the sample files
to work with Watcom C/C++ version 10.6. Once these changes are made,
the makeallw.bat batch file can be run to make the sample programs.
See the readme file in the WATCOM directory of the DirectX 2.0 CD for
more information.
"Avocado Green" (truongmn@UCUNIX.SAN.UC.EDU) wrote the following on the
WATCOM List server:
Here are some simple steps in using the Watcom IDE (10.6) to compile
and run the DirectDraw example (DDEX3) included with the DXSDK. I
thought I'd save someone a few hours from messing with the make files.
0. Run the Watcom IDE (run it from the DOS box command line if it'd
make you feel less guilty.)
1. Select menu option "File->New Project"
Select the C:\DxSDK\Samples\DDex3 directory and enter
"ddex3.wpj" as your project name
Note: If you installed the DirectX SDK in another directory
other than C:\DxSDK, make the changes as appropriate.
2. Enter "DDex3" as the target name,
"Win32" as Target Environment, and
"Windowed Executable [.exe]" as the Image Type.
3. Select menu option "Targets->Target Options->Windows Linking Switches"
Go to "2. Import, Export and Library Switches",
In field "Library directories(;):[libp]" enter "..\..\lib"
In field "Libraries(,):[libr]" enter "ddraw.lib"
4. Add these source files into your project:
..\misc\ddutil.cpp
ddex3.cpp
ddex3.rc
5. Highlight the "ddex3.cpp" file and select menu option
"Sources->Sources Options->C++ Compiler Switches"
In field "Include directories:[-i]" add ";..\..\inc;..\misc;..\include"
so it should read
"$(%watcom)\h;$(%watcom)\h\nt;..\..\inc;..\misc;..\include"
...of course you've set your Watcom environment variables already,
right?
6. Repeat step 5. for ddutil.cpp also, or you can perform step 5. on the
folder (.CPP) (representing all .CPP files)
7. Select menu option "Target->Make" and watch the few warning mesages
go by
8. Select menu option "Target->Run" and enjoy your Watcom compiler
running something other than "helloworld.c" (well, for me anyway)
Other Direct X specific FAQ's may best be answered at the following URL:
http://www.microsoft.com/mediadev/msupport/mergfaq.htm#DirectDraw
----------------------------------------------------------------------------
Q09. How do I program for Intel's RDX using WATCOM C/C++?
A09. Intel's RDX is a library for composing sprites, playing back sound
and video. I don't know the details, however Hossain Morshed of Intel
Corp. has responded to the inquiries of Ed Mueller and what appears to be
the popularity of this FAQ with the following information:
The following is a description of how RDX can be used with Watcom
compiler.
Thanks,
Hossain Morshed
Intel Corp.
Intel(R) RDX and Watcom* C/C++
06/12/96
The RDX v2.1 Developer's Kit has been tested with Watcom C/C++ (v10.6).
It should be available for download this June (6/96) from the Intel RDX
Web Site (http://www.intel.com/ial/rdx/).
If you are using Watcom C/C++ with the RDX v2.1 DLLs, you will need to
link your application to Watcom specific import libraries. You can
create Watcom import libraries for the RDX DLLs by using the Watcom
WLIB tool. For example, the following commands create the necessary
import libraries (provided that WLIB is in your path and the DLLs
reside in the C:\RDX\SYSTEM\RELEASE directory):
wlib dmix.lib +c:\rdx\system\release\dmix.dll
wlib dinoav.lib +c:\rdx\system\release\dinoav.dll
wlib dino2d.lib +c:\rdx\system\release\dino2d.dll
If you are trying to use Watcom C/C++ with the RDX v2.0 DLLs, we
suggest you use the RDX v2.1 Developer's Kit. Besides providing many
new features and enhancements, it will also allow you to link your
applications successfully to the data structures that the DLLs export.
However, if you want to use Watcom C/C++ with RDX v2.0, it is possible
to do this successfully by modifying the DINO.H and DINOAV.H header
files so that they declare the FX GUIDs using the DEFINE_GUID macro all
of the time and don't specify the DINO_SYMBOL/DINOAV_SYMBOL prefix.
Then all you have to do is modify one of your application's C or C++
modules to include the INITGUID.H header file before inclusion of
DINO.H and DINOAV.H. This will cause the FX GUID data structures to be
declared in that module and thus be available to all of the other
modules in your application.
Note: To successfully compile the RDX v2.0 sample programs a similar
modification is necessary, in addition to a few other minor changes due
to differences in how Watcom C/C++ and Microsoft Visual C++* compile
source code.
The RDX Developer's Kit does not provide Watcom specific make files for
the sample programs.
* Other product and corporate names may be trademarks of other
companies and are used only for explanation and to the owners'
benefit, without intent to infringe.
It appears that to use RDX, you must enter into an agreement with Intel
that involve NDA's of some sort. Refer to the URL given above for more
information.
"Avocado Green" (truongmn@UCUNIX.SAN.UC.EDU) wrote the following on the
WATCOM List server:
Here are some simple steps in using the Watcom IDE (10.6) to compile
and run the Intel RDX 2.1 (2.0 did not work fully with Watcom)
example (EVENTS) included with the SDK.
Note: The "lite" version of the RDX 2.1 SDK does not contain the
.bmp files needed to build the examples, so you'd probably
want to ask Intel for their RDX CD instead of downloading
the 63MB archive.
I'm not sure if Intel has got v2.1 on CD yet, so if you have
v2.0, install that, then install the 2.1 "lite" version on top
of it.
1. Create the Watcom import library files by running wlib like so:
- cd to \RDX\Lib (if you installed the SDK there)
- move the .lib files there to some other directory, you should
have nothing in \RDX\Lib
- run:
- wlib dmix.lib +c:\RDX\SYSTEM\RELEASE\dmix.dll
- wlib dinoav.lib +c:\RDX\SYSTEM\RELEASE\dinoav.dll
- wlib dino2d.lib +c:\RDX\SYSTEM\RELEASE\dino2d.dll
- wlib rdxam.lib +c:\RDX\SYSTEM\RELEASE\rdxam.dll
There's a \RDX\SYSTEM\DEBUG directory with these same .DLL,
Guess these are the debuging version of the .DLLs
2. Run the Watcom IDE (run it from the DOS box command line if it'd
make you feel less guilty.)
3. Select menu option "File->New Project"
Select the C:\RDX\Samples\Events directory and enter
"Events.wpj" as your project name
4. Enter "Events" as the target name,
"Win32" as Target Environment, and
"Windowed Executable [.exe]" as the Image Type.
5. Select menu option "Targets->Target Options->Windows Linking
Switches"
Go to "2. Import, Export and Library Switches",
In field "Library directories(;):[libp]" enter "..\..\lib"
In field "Libraries(,):[libr]" enter "dmix.lib dino2d.lib"
6. Add these source files into your project:
events.c
help.c
winmain.c
events.rc
7. Highlight the folder (.C) (representing all .C files) and select
menu option
"Sources->Sources Options->C++ Compiler Switches"
In field "Include directories:[-i]" add ";..\..\include"
so it should read "$(%watcom)\h;$(%watcom)\h\nt;..\..\include"
8. Select menu option "Target->Make"
- wow not even a warning message.
9. Select menu option "Target->Run"
- Kill the dweebs
----------------------------------------------------------------------------
Q10. Is the code WATCOM C/C++ produces the fastest/tightest?
A10. The WATCOM C/C++ compiler is generally regarded as among the best in
terms of code generation. For example, it produced significantly better
code than any 16 bit compiler. In an article in PC Magazine a few years
back, benchmarks indicated WATCOM C/C++ version 9.5 had the tightest and
fastest code among such compilers as Visual C++, Borland C/C++, Metaware
Hi C, Zortech and Symantec (by a wide margin). WATCOM's compilers have
generally lead in the performance category in all brands and versions of
their compilers starting with version 7.x, however among the more modern
compilers it appears as though both "djgpp" and "Visual C++ 4.x" produce
pure C code compilation which is as good (if not slightly better) than
WATCOM's.
However, among the reasons for chosing WATCOM for high performance code
generation is also its ability to use inline assembly language, the
disassembly tool and its ability to collect accurate performance profiling
information. These tools are an indespensible part of the a "pedal to the
metal" coder.
Be sure to follow the recommended switches for compiling your code that
are given in the documentation. Options such as "assume no aliasing" and
using "reciprocal and multiply" for floating point divides can cause the
compiler to make assumptions about your code that have great performance
impact even though the code generation techniques fall outside the rules
of the ANSI spec. You should be sure you understand all the options for
optimization.
----------------------------------------------------------------------------
Q11. How do I use WATCOM's tools to help me optimize my code?
A11. WATCOM comes with 3 tools that make the code optimization process an
easy one: Execution sampler/profiler, disassembler and debugger.
There is a commonly held belief that in most applications 10% of your code
will be executed 90% of the time. That is to say, most applications tend
to be bottlenecked, with the tightest bottleneck causing the greatest
performance penalties. With WATCOM C/C++ this still holds true, but not
to such a severe extent, since WATCOM tends not to produce any "bottle-
necky" code.
It is for this reason that your first step in your optimization phase
should be to profile your code. Even if your project is half complete,
and not representative of its final form, execution sampling and profiling
can often pinpoint unexpected bottlenecks in your code.
The execution sampler works by executing along with your code, randomly
gathering instruction addresses during its run. The profiler then converts
the sample data into a chart which clearly shows what functions were
called. You can zoom into each function to see what lines of code are
being executed, and keep doing that right down into assembly level. To do
this of course you have to compile your code with line number debugging
information (/d1 or /d2.)
Not too surprisingly, data collected on Pentiums may show a sample data on
machine instructions one after where the real execution occurred. This is
because the Pentium tries to execute instructions in pairs and the delays
in one instruction may appear to be passed to the instruction it is paired
with.
The other tool is the disassembler. Using it you can see all the
instructions compiled and correlate them their source lines. WATCOM C/C++
generally only uses 1 cycle instructions. However, in order to strike a
reasonable balance between code size and performance, WATCOM also uses some
complex instructions. The most notable being: mul, imul, div, idiv, movzx
and movsx. Simply scanning for these instructions can help you see where
your data structures and type mismatching are causing sub-optimal code to
be produced.
Finally the debugger is a simple tool not only for catching your bugs but
for tracing through your code to see the path it is really taking. Most
of the time the execution path for small projects is fairly clear to the
programmer. But when multiple programmers are involved or your code
becomes very fragmented, it is not so clear. Very often, simply tracing
through your programs can lead you into good insights about the
performance of your program.
These general principles can be applied to any compiler, however few
compilers can rival WATCOM in these tools.
For information about Pentium optimizations in general, Agner Fog has
written up an excellent reference work which can be found on the following
URL: http://www.geocities.com/SiliconValley/9498/p5opt.html
----------------------------------------------------------------------------
Q12. How does WATCOM C/C++ compare with other C compilers?
A12. WATCOM C/C++'s biggest strengths right now are the performance tools
and its ability to do cross-platform development. With WATCOM the concept
of a single project targetting multiple platforms is a practically
realizable goal. Their 32 bit compilers have been around since about
1992, years before Borland, or Microsoft had PC based 32 bit compiler
technology (apparently DJGPP/DJGCC had it, but was highly obscure by
comparison.) However, their recent acquisition by PowerSoft has given
them a highly acclaimed RAD tool (Optima++) that is based on top of the
WATCOM C/C++ compiler; a joining of technologies that has caught their
competitors with their pants down.
By comparison, Microsoft is currently only supporting VC++ which can
create targets for Windows and DOS. An extra dos extender (at extra cost)
is required for 32 bit DOS code (I believe Pharlap's TNT is the only one
really supported.) DOS development is not supported by the IDE. Version
4.x requires 24MB of memory to run smoothly (as opposed to WATCOM's
requirement of 8MB.) Microsoft has gotten into a habit of tweaking their
compilers and operating systems in lock step; creating more and more
conventions and odd things like "Thunking" (a Windows OS and VC++ specific
way of performing 16<->32 bit execution segment translations.) Users of
Microsoft compilers (and products in general) become locked into their
level of technology be it good or bad. They also get locked into their
"vision" as they are clearly pointing developpers to Windows 95 and
Windows NT. Of course OS/2, QNX and other platforms will never be
supported. The code generator for version 4.x compares favorably with
WATCOM's, but the lack of reliable performance tools and the klunky
out-dated method of inline assembly keeps VC++ from being the performance
compiler of choice.
Borland is looking straight into the abyss these days. I am not very
familliar with their most recent products, but their strength has always
been their IDE and compile speed. But the latest WATCOM C/C++ compilers
have closed these gaps considerably. Borland attempted to diverge from
MFC with "OWL". They also stopped support for DOS for a brief period.
Their PowerPak solution does not completely map in the first megabyte of
memory which is problematic, and requires a lot of support to work around.
Last I heard, Borland had dropped PowerPak support completely. These
mistakes have cost Borland valuable time and their compiler technology has
suffered as a result. They themselves have practically admitted this and
have thrown their efforts behind "Delphi" (a RAD tool layered on top of
their non-standard Object Pascal.)
DJGPP beats all these compilers in two places: code generation and price.
(It appears to produce the tightest code, and costs $0.) However, it
falls flat on its face in terms of compile speed, interface and third
party support. DJGPP has only recently been robust enough to produce
targets that work under both DOS and Windows DOS boxes, and the currently
available Windows native 32 bit support is still in development stages
(and is a separate compiler.) The IDE is still in development and don't
count on MFC support. User support is there through the internet.
Standard game libraries such as WGT, Fastgraph and Direct Draw have not
been ported, and are not likely to ever be. (On the other hand, SVGAKit
from SciTech has been ported, very recently.)
I haven't heard so much as a peep from Metaware. As for Symantec, I hear
they are doing java. Its likely that in the face of VC++ these companies
felt they simply couldn't compete. Indeed its hard to see how any other
compiler besides WATCOM C/C++ will survive Microsoft's latest product
juggernaut.
----------------------------------------------------------------------------
Q13. How do I debug DOS4GW apps under Windows 95?
A13. WATCOM implements this using two DOS boxes. This scheme allows the
target program to retain full control of its VM without interference from
the debugger (for, example, you should be able to debug apps which take
over the screen without any problems besides Window's ability to
virtualize that mode.) So in theory, debugging should be more reliable.
In one DOS box you run the windows server:
winserv -trap=rsi
and in the other you run the debugger:
wd -trap=win <executable name and arguements>
This is essentially the same procedure used for remote debugging over a
serial cable. Be sure that the [386enh] section of your system.ini
contains the line "device=wdebug.386". If you have problems try
explicitely entering the path for wdebug.386 (it should be %WATCOM%\binw)
and make sure that this file actually exists. Be sure you are running
wd.exe from the %watcom%\binw directory, not the %watcom%\binnt directory.
The "rsi" thing stands for "Rational Systems incorporated" which is the
former name of TenBerry Systems, so don't be surprised if this changes to
"tbs" in future versions of WATCOM C/C++. For Windows NT, the server
should be run as "vdmserv -trap=rsi" and the debugger should be run as "wd
-trap=vdm <target command line>". Similar solutions exist for other OS's
(Thanks to Eric Kenslow, "Gothmog" and Tomas Likens for the majority of
this information.)
----------------------------------------------------------------------------
Q14. How do I debug WATCOM apps using Soft-ICE?
A14. Richard Horrocks writes:
I don't know about 9.5, but for 10.0+ just compile with "-d3 -hc", link
with "debug codeview opt cvpack", then run DBG2MAP on the executable and
finally MSYM to get a symbol file that SoftIce can read (I can't verify
that this works with source line numbers as I get "out of memory load
source file" errors).
As far as I know, SOFT-ICE's symbol memory can be expanded by setting the
'SYM=###' in the *.DAT configuration file (in SOFT-ICE/W its the
WINICE.DAT) Refer to the SOFT-ICE documentation for more information.
----------------------------------------------------------------------------
Q15. How do I enable virtual memory for my DOS4GW application? How do I
know exactly what interrupts dos4gw handles all by itself? How do I know
exactly what a programmer have to do, using dos interrupts from protected
mode?
A15. These and other DOS4GW specific questions are answered in the file
%WATCOM%\DOS4GW.DOC, and in the online help under the DOS/4GW section of
the user's guide.
----------------------------------------------------------------------------
Q16. Why doesn't WATCOM use "_asm" for inline assembly like Microsoft and
Borland? Afterall isn't that standard?
A16. Well, first off, that most definately is *not* standard (as in ISO
or ANSI.) Since the Microsoft/Borland _asm construct falls outside the
ANSI standard, it promotes the generation of C sources which are not
portable. WATCOM instead uses the ANSI sanctioned "#pragma" directive.
(See discussion latter for why WATCOM's method is intrinsically more
portable than the _asm method.) The file:
ftp://ftp.powersoft.com/pub/c_cpp/general/asm.txt
explains WATCOM's reasoning more fully.
----------------------------------------------------------------------------
Q17. Why does my code work only when I compile with debugging info on?
A17. Dom Laflamme asked this question on the USENET newsgroup
"rec.games.programmer" and I gave the following response:
Dom Laflamme wrote:
> Hi,
> I've been coding a game engine for the passed 3 months. It works
> fine and it's fast. Execept that when I turn the "Debugging Info" off
> in Watcom, _nothing_ works, it just crashes. Since I cant debug the
> thing properly because of lack of debuging info, I face a truly
> problematic situation!
There is a big difference in the code generated by using the /d2 debug
switch and no debugging. /d1 is supposed to be nearly identical to
using no debugging but has significantly less deugging information.
WATCOM's optimizations are *NOT* broken as someone else posted. But
they are truly aggressive.
WATCOM recommends setting: /otexan, and each switch (t, e, x, a, and n)
is sufficiently documented in the online help. I'm guessing that you
have these setting all on since "it's fast". This recommendation is
based on the assumption that you are writing correct ANSI-C and that you
are not stepping outside the bounds to the point of breaking one of
WATCOM's optimization strategies.
As a simple test, trying setting all the optimization switches off (as
well as the debugging switch off.) If your engine starts working again,
then turn the optimization switches back on one at a time until your
engine breaks again. Keeping in mind that the "a" switch (assume no
aliasing) is the only one in which correctly written (but really brain
dead) ANSI C can fail to execute.
Once you have isolated the switch, read the documentation on the switch
very carefully. Try to isolate the problem area and disassemble the
code with each optimization switch. Once you see the difference, you
should be able to figure it out.
You problem is likely one of three things: (1) Simple mistake, like
dereferencing a bad pointer, or accessing outside the bounds of an
array, (2) You are misunderstanding the meaning of the "volatile" ANSI C
keyword and hence are misusing it, or not using it (the most likely)
when you should. (3) You are aliasing pointers to non-disjoint
structures and WATCOM is reordering an inner loop in too aggressive a
manner (you will have to either recode or remove the "a" switch
entirely.)
I have seen all three cases in my own work and in the work of others. I
found that using WATCOM is an exercise in "re-learning" how ANSI C
really works.
----------------------------------------------------------------------------
Q18. What is FLAT memory model? What is the advantage of a 32 bit
compiler such as WATCOM C/C++ over 16 bit compilers? What are the
differences? Will I be able to move my 16 bit DOS code straight over to
32 bit?
A18. WATCOM C/C++ can compile for either 16 bit or 32 bit. The compilers
are named wpp/wcc/wcl and wpp386/wcc386/wcl386 respectively for 16 bit
and 32 bit compiliation. Every DOS programming model under the sun is
implemented: TINY, SMALL, COMPACT, MEDIUM, LARGE, HUGE (the 16 bit
models) as well as FLAT and LARGE32 (the 32 bit models).
WATCOM C/C++'s default 32 bit DOS memory model is FLAT memory model. FLAT
memory model is an analogue of TINY model for 32 bit programs. ES and DS
are set to the same selector which points at the base of memory and maps
all 4GB of address space. CS is a selector that points to all of memory
like DS and ES, but has the execution attribute set, meaning that it
cannot be written to directly. SS is set to a special stack segment to
make stack overflow easier to detect. This set up allows you to, in
nearly all situtations, ignore segment/selector registers completely. FS
and GS are available for applications to use as they see fit and by
default are set to 0. (Hint: Be sure to check the values of these
selectors whenever you are debugging a failure in your code. These
selectors may change as a result of ill-behaved interrupt vector calls,
and hence may need to be saved and restored properly (see the #pragma
discussions elsewhere in this FAQ))
Unless you are dealing with interfacing to external 16 bit resources (such
as APIs implemented through interrupts) you never need to deal with 64K
segment limits, or strange keywords like FAR, NEAR or MK_FP. Pointers and
int's are both 32 bit, and while its not advisable, you can cast between
the two and still be portable to most platforms (16 bit x86 environments
and 64 bit DEC Alpha environments being the most notable exceptions.)
The extra bandwidth/precision you get for using a 32 bit coding model over
a 16 bit one speaks for itself. 32 bit instructions executed from 32 bit
segments do not need instruction overrides. Beyond that only TINY and
SMALL models (from the 16 bit model choices) compare with the low overhead
for context switches. That is to say, the only 16 bit models that also
don't require selector loads for new data pointers or function calls are
restricted to 64K of data and/or code.
Familliar DOS/BIOS data areas such as 0A000:0000 and 004f:0000 have been
mapped in the most natural way: 16*segment+offset. So VGA space is now
at _FLAT:0x0A0000 and the standard BIOS area is now at _FLAT:0x04F0. But
this mapping doesn't necessarily hold true for the rest of system memory.
This is actually a good thing since it allows for linearly mapped graphics
cards to have their address range placed at a convenient place, namely the
end of your conventional memory. (Or in the case of Windows; usually a
special address range with certain OS specific characteristics.)
(It is important to note that the construct MK_FP(0xA000,0); doesn't have
the same meaning and will *NOT* correctly map the screen to a usable
pointer. Use (char *)(0x0A0000) as just described.)
This sudden ease of implmentation for everything is actually likely to
make the job of porting from 16 bit DOS quite involved for many
applications. This porting procedure would mostly be an exercise in
*undoing* all the 16 bit nonsense that was being done previously.
----------------------------------------------------------------------------
Q19. I am getting this weird error message ...
A19. Lets go through some of the more common ones:
(1) When I run my program I get something like:
DOS/4GW Protected Mode Run-time Version 1.97
Copyright (c) Rational Systems, Inc. 1990-1994
DOS/4GW error (2001): exception 0Eh (page fault) at 237:825A401F
TSF32: prev_tsf32 5290
SS 23F DS 23F ES 23F FS 0 GS 87
EAX FFFFFFFF EBX 8244A380 ECX 0 EDX 0
ESI 824493A1 EDI 8244939C EBP 8244A374 ESP 8244A370
CS:IP 237:825A401F ID 0E COD 6 FLG 10202
CS= 237, USE32, page granular, limit FFFFFFFF, base 0, acc CFFB
SS= 23F, USE32, page granular, limit FFFFFFFF, base 0, acc CFF3
DS= 23F, USE32, page granular, limit FFFFFFFF, base 0, acc CFF3
ES= 23F, USE32, page granular, limit FFFFFFFF, base 0, acc CFF3
FS= 0, USE16, byte granular, limit 0, base 0, acc 0
GS= 87, USE16, byte granular, limit FFFF, base 18DD0, acc F3
CR0: unavailable
Crash address (unrelocated) = 1:0000001F
This means that you have an error in your program. If the address given
in the last like looks like 1:000????? (basically segment 1 and a
reasonably small sized offset) then chances are you can run this under the
debugger and have the address of your error shown to you. If even the
address looks like its off in the weeds, remember that WATCOM's debugger
allows you to crawl up the execution stack to see how the crash was
arrived at.
If running the debugger is out of the question or somehow problematic for
you then you can generate a map file by putting "option map=myprog" on
your link command line, or putting "/fm=myprog" on your wcl command line.
This is most useful when you are compiling with debug info ("/d2" on your
compile command line.) The resulting myprog.map file is correlate the
line numbers in your program to the "Crash address" given above.
Often the target address will be in a library function. This generally
means that either the parameters passed to the function are bogus, or some
global state that the function depends on has become damaged. Global
state is hard to be debug, but not impossible. See "Q20. I am having
malloc troubles. It seems that I am trashing the heap but I don't know
how to debug it." later on in the FAQ.
But most of the time you are simply accessing memory you shouldn't be
(past end of an array, stuffing a pointer without first mallocing it,
inadvertantly corrupting a pointer that you use later.) Remember,
pointers are not in "far" format, but rather in "_FLAT" format. So
0x0A0000000 is not the address of the VGA frame buffer, 0x0A0000 is.
(2) I type:
wcl386 /l=dos4g hello.c
and get back:
WATCOM Linker Version 10.6
Copyright by WATCOM International Corp. 1985, 1996. All rights
reserved.
WATCOM is a trademark of WATCOM International Corp.
Warning(1107): file __WCL__.LNK: line(2): undefined system name: dos4g
loading object files
searching libraries
Error(3002): ** internal ** - format not decided
Error: Linker returned a bad status
This means that when you installed WATCOM C/C++ you did not select 32-bit
DOS target. You can run the installation procedure again to do an
incremental install of 32 bit DOS compiler support.
(3) I'm using the IDE and am trying to compile an example program that comes
with "SupermundoGraph" and am getting messages like:
wlink SYS dos op m op maxe=25 op q op symf @smg_ex1.lk1
Warning(1028): smg_move_ is an undefined reference
Warning(1028): smg_drawmap_ is an undefined reference
file timmy.obj(C:\smg\src\smg_ex1.c): undefined symbol smg_resize_
file timmy.obj(C:\smg\src\smg_ex1.c): undefined symbol smg_setclip_
"undefined reference" and "undefined symbol" indicate that something has
gone wrong in the linking process. I am not very familiar with the IDEs
but, chances are you have not added in the SupermundoGraph library
properly. According to the v10.0 IDE help documentation, you simply add
the library (*.lib) as if it were a source file.
Also watch that you have selected the right directories for your project.
I usually set up my directories and build my project sources before
invoking the IDE (in the rare occasions that I have ever used the IDE.)
If you are not careful, you will end up building projects right in the
compiler's own Windows tool directories, which makes for file maintenance
headaches sooner or later.
If that's not it, then perhaps the example is not compatible with your
version of WATCOM C/C++. In this case, you should contact the library
vendor and inform them of this problem.
(4) I am getting linker errors from wpp386 that make no sense. I have
everything externed and properly prototyped as far as I can tell.
On possibility is that you are trying to combine C and C++ code. If it is
your intention to only write C, and not import C++ libraries, then you
should use the wcl386 or wcc386 compilers. If you want to write C++ code,
you cannot simply mix C and C++ directly. To import C code into a C++
project you must prototype them as extern "C" { } as follows:
extern "C" // c must be a capital C
{
extern void Set_320_200();
extern void Put_Pixel( BYTE Color, WORD x, WORD y );
}
The extern's publicize the symbol, and the "C" declares them as C symbols
so that they are linked without C++ attributions. Thus they act as C
symbols, not C++ symbols. This means their names are not mangled in the
objects, they cannot be overloaded, etc., etc.
Thanks to Lassche MA (mlassche@cs.vu.nl) for verifying this, and thanks to
Eric Kenslow for giving more a detailed explanation of extern "C".
----------------------------------------------------------------------------
Q20. I am having malloc troubles. It seems that I am trashing the heap
but I don't know how to debug it.
A20. Someone on rec.games.programmer asked this question and I gave this
as the response:
Apparently somewhere in version 10.0 or 10.5, WATCOM had a problem with
mallocing that has been fixed in a subsequent build. It is likely that
a patch for it exists on their WWW site.
Nevertheless, I believe that bug was an extremely obscure one with the
"free" command and is unlikely to be your problem. Dealing with a
trashed heap is difficult with any compiler, but WATCOM makes it
particularly challenging because of its "frugal" heap memory tracking
system. If you do a little debugging/reverse engineering, you will see
that a WATCOM memory allocation tracks the size in the int (signed long)
just before the actual allocation itself. So (ptr=(int*)malloc(99))[-1]
should be 99. The malloc/free functions use this and this alone to
track the heap so if you are trashing memory, especially these sizes,
you will start dying really soon.
I found that the WATCOM debugger is particularly good at tracking down
precisely this sort of problem. Allow me to tell you a story:
Once upon a time I had a memory corruption in a large convoluted program
I was writing. So I started debugging by putting a wrapper around the
"malloc" and "free" functions that added an additional size to test the
validity of each malloced size against when I use it (which I put on the
*other* side of the allocation.) I put a test in the place where my
program was accessing it and GP faulting. I simply output a message
indicating that the memory was trashed. Using the debugger I put a
break point on the error message printer. Then I used the "reverse
execution" feature to get me back to the failed memory size comparision
and noted the machine address of the WATCOM size pointer. Then I reset
the program and put a breakpoint on access to that memory address. It
turns out that my program legally accessed it several times (on the
order of a thousand.) So I used the breakpoint "counter" to help me
zero in (essentially a binary search) on the number many times this
memory was accessed before the crash occurs. By setting the counter
appropriately, I found the code which was pounding on the size and
rectified it. Total time spent was about 1.5 hours which is not bad for
a bug of this complexity (most of the time was spent on other desparate
attempts to find the bug *before* diving in and trying the above
procedure, which took < 10 mins.)
I can't praise the WATCOM debugger enough for enabling me to do the
above procedure. In particular, the reverse execution feature gives me
unparalleled power (with the exception of Soft-ICE, which of course,
gives you much more power) for determining my context. Mixed assembly
and source level debugging allowed me to reverse engineer WATCOM's
malloc method lickedy split.
BTW, the bug in my program was simple. I was accessing a pointer before
mallocing it.
Paul Keys responded to the post above with a very good suggestion:
Watcom has functions that can be used to debug the heap. Functions such
as _heapset, _heapchk, _heapwalk, are indespensible. Using _heapset I
have managed to find cases where I was using pointers to memory that had
been mistakenly freed. With _heapchk, I have tracked down where the
heap lost its integrity. And using _heapwalk, I was able to track down
some rampant allocation that was slowly gobbling up all available
memory.
Finally, it should be noted that on the WATCOM C/C++ file site there is a
sample program for diagnosing memory errors. This program is located at the
following URL: ftp://ftp.powersoft.com/pub/watcom/c_gen/memcheck.zip
----------------------------------------------------------------------------
Q21. How do I write directly to graphics memory?
A21. As mentioned above, the base of VGA memory is mapped at 0x0A0000.
The ports can be accessed via the outp() function, so even setting up Mode
X is no big deal. For an example of this see:
http://www.geocities.com/SiliconValley/9498/modex.zip
CGA and EGA are no more challenging than VGA.
SVGA modes have their own special problems. The examples in Ferraro's
book on VGA's and SVGA's can be easily adapted to WATCOM C/C++, even in
pure C, with the exception of the VESA SVGA stuff. Revision 1.2 of the
VESA SVGA interface (the interface most widely supported by SVGA's out
there) requires a 16 bit memory allocation for a data buffer and a 16 bit
call or interrupt to the "Bank Switch" procedure (my own investigations
lead me to find that the WinPtr call was not reliable on many graphics
cards and thus I stuck with the interrupt). Many novices (including
myself, when I first tried it) make the mistake of thinking that they can
just pass in some appropriately cooked values into the required registers
as the VESA spec requires and just call int 10h. Unfortunately this does
not work when the "es" register has to be stuffed with the segment for the
buffer that VESA fills in with mode info. You need a protected mode to
real mode translation API to make dos allocations and simulate real mode
dos interrupts. These are both achieved by using DPMI which is discussed
elsewhere in this FAQ (see Q23.)
Revision 2.0 of the VESA SVGA interface has a 32 bit interface and also
allows the option of mapping the entire frame buffer to a single
contiguous linear memory range. The VESA SVGA specs are available at:
ftp://x2ftp.oulu.fi/pub/msdos/programming/specs/vesasp12.zip and
ftp://x2ftp.oulu.fi/pub/msdos/programming/specs/vbe20.zip
The WATCOM C/C++ file area also has an example URL for getting you started
using VESA:
ftp://ftp.powersoft.com/pub/c_cpp/general/newvesa.c
If you require linear memory access to SVGA, then your choices are: (1) use
a VESA 2.0 interface (the easiest way), (2) Map in the graphics controller's
physical memory yourself (the hardest way), or (3) Use a more powerful DOS
extender (than DOS4GW) that supports the DPMI phys to linear map function
(the expensive way, see next question for more information.)
Programming a graphics controller to use its specific functions requires
getting specifications for the graphics controller themselves.
----------------------------------------------------------------------------
Q22. How do I install a mouse event handler?
A22. There is an example of this on the WATCOM C/C++ web site general file
page. The URL is ftp://ftp.powersoft.com/pub/watcom/c_gen/tstmouse.c The
general idea is just to make sure the declaration protocals have it taking
the right registers as its parameters, stack checking is turned off and DS
is reloaded.
----------------------------------------------------------------------------
Q23. What is DPMI and what role does it play in using WATCOM C/C++? How
do I communicate between the 16 bit world and 32 bit world on my PC?
A23. DPMI stands for "DOS Protected Mode Interface" and was dreamed up by
Intel and Microsoft. It was a method for extending DOS's functionality
for supporting 32 bit programming at the lowest possible level. Windows
is an example of a program which implements and leverages the DPMI
interface to enable "Enhanced Mode" and 32 bit DOS Extended applications
to run under DOS boxes. (QDPMI, CWSDPMI and DOS4GW itself are other
examples.)
For most purposes DPMI essentially is an API for setting up 32 bit
selectors, and call gates between 16 and 32 bit execution segments. A
version 0.90 (the one used by Windows) specification is available at:
ftp://x2ftp.oulu.fi/pub/msdos/programming/specs/dpmispec.arj
(you need 'ARJ' to decompress this file; its available elsewhere on x2ftp)
An online 1.0 specification can be found at:
ftp://x2ftp.oulu.fi/pub/msdos/programming/specs/dpmi100.zip
Also be sure to check the WATCOM C/C++ file area directory located at
ftp://ftp.powersoft.com/pub/watcom/c_gen
which has several relevant example files: rintcall.c, memory.c, and
dpmi800.c
The major differences between 0.90 and 1.0 is that 1.0 servers must return
with exact error codes in the event of a failure. Among its most common
uses are: allocating 16 bit memory and calling a 16 bit interrupt which
takes a 16 bit segmented address for a data buffer (ordinarily DOS4GW
and/or WATCOM's heap manager will not "malloc" from DOS memory, so it
essentially goes wasted.) These are both required for supporting VESA
SVGA 1.2. You may notice that among the many messages printed on DOOM's
fake "DOOM OS" init screen is a mention of DPMI allocations. The
programmers at "id" probably wrote their own memory manager which uses
conventional memory in addition to regular heap memory.
The major short coming of DOS4GW is that its an incomplete implementation
of DPMI (0.90). The WATCOM C/C++ users's guide describes what DPMI
functions *are* implemented in the "INTERRUPT 31H DPMI Functions" chapter.
DOS4GW even steps outside of the bounds in the sense that unsupported
functions do not simply return with the carry flag set indicating an error
(even though it has not completed the DPMI function.) Forunately the
latest DOS4GW implements both the DOS alloc function and the simulated DOS
interrupt call, which are sufficient for setting up rudimentary 16 bit
communication. If another DPMI manager is present, however, DOS4GW will
not set up its own DPMI server. (I shelled out $150 for the CauseWay DOS
Extender which is far more robust and feature rich.)
So how does one actually coordinate 16 and 32 bit components together?
Allow me to explain one method. All 32 bit DOS executables are bound with
a 16 bit kick-start program. This kick-start program is, by default,
named WSTUB.EXE and is located in the %WATCOM%\BINB directory. Obviously
you can change the contents of this file to anything you like (you can
probably do this without mucking with %WATCOM%\BINB\WSTUB.EXE directly,
but rather using the WBIND command, but I have not investigated this
fully.)
The 16 bit source code for WSTUB is also supplied, which makes the
kickstarting procedure fairly clear (starting with version 9.5, WATCOM
included both that 16 and 32 bit versions of their compiler in the same
package.) It basically parses the command line arguments and passes
control to DOS4GW with itself as the first parameter followed by the rest
of the regular parameters. You can write all your 16 bit components in
the stub, passing critical pointer values as command line parameters to
the 32 bit portion. The pointers could point to anything, including 16
bit function entry point addresses and data areas. The 32 portion would
do the simple math to convert the pointers and can pass control back to
the 16 bit stub functions using the DPMI 16 bit function call simulation
call. Voila!
The reason I've described the above procedure is that I've seen others take
a less savory approach that I'd just as soon see avoided in the future. In
at least one sound library I noticed that the implementer wrote a 16 bit
TSR that had to be executed beforehand. Clearly, an unsanctioned or
unreliable method of communication between the 16bit TSR and 32bit library
was being used. Using the stub method is much cleaner.
Why would you ever want to paste 16 and 32 bit code together? Well, the
main reason would be that you have a large database of 16 bit code that is
most logically accessed as if coming from an interrupt event. I've also
heard rumours to the effect that using DMA is a 16 bit only operation, but
I'd have to investigate that more fully before confirming it.
For example, you might have a substitute mouse driver written in 16 bit code
that you don't want to run as a separate TSR because you want to retain the
old mouse ISR. So you could install it at the start of WSTUB, spawn the 32
bit process, then deinstall it when you come back.
Personally, I've modified WSTUB.EXE in minor ways, but in all honesty, I
have to admit that I have not tried the above procedure myself.
Nevertheless, I cannot see any other reason WATCOM would expose the 16 bit
source for WSTUB.EXE. If somebody ever implements (or has already done
so) this idea successfully, I'd like to know about it.
----------------------------------------------------------------------------
Q24. What if I really need to compile a 16 bit model program?
A24. Starting with version 9.5, WATCOM includes both the 16 and 32 bit
compilers in a single package. The 16 bit compiler executables are
wpp.exe, wcl.exe and wcc.exe, while the 32 bit compilers are wpp386,
wcl386.exe and wcc386.exe. It should just be a matter of changing your
makefile or flipping an IDE switch.
----------------------------------------------------------------------------
Q25. Why do WATCOM's results and Visual C++'s results differ on the same
source code? Why does WATCOM implement the default signedness of chars
different from everyone else? I am having difficulty porting code to
WATCOM C/C++?
A25. A list of these differences can be found in the online help. Here's
a list of the major gotcha's:
- To get around the signedness default be sure to pass a "/j" on the
command line.
- WATCOM will, by default, use registers for its parameter passing
convention which makes it incompatible with regular COFF format libraries
and object files. However, adding the extra declaration information via
"#pragma aux <function> frame;" will force WATCOM to pass parameters to
the function via the stack.
- WATCOM's "wmake" utility parses a makefile format that is entirely
different from Microsoft's. WATCOM decided to mimick UNIX as closely as
possible, while Microsoft went ahead and made their own standard.
- If you do asynchronous variable updates (such as modifying global
variables in an ISR), you *need* to declare your variable as "volatile".
Other C compilers optimization strategies act as if all variables were
declared volatile, and can mislead you into thinking it is unneccessary to
declare your variables this way.
- In general, WATCOM's C/C++ compilers tend to be more stable, however one
notable exception was the initial release of version 10.0. But WATCOM had
patches available in a couple months which fixed its most outstanding
problems. Relatively speaking, WATCOM's compiler is fairly robust and
more ANSI compliant than Visual C++ which can explain most discrepencies.
----------------------------------------------------------------------------
Q26. Can I link external assembly files together with my C files?
A26. WATCOM's linker can accept .OBJ files in its own format or in the
standard intel format. So using a separate assembler should not cause any
extra unneccessary complications. Earlier versions (9.0) of the compiler
required the use of the "WOMP" utility to convert object formats. Starting
with version 10.0, WATCOM C/C++ also comes with an external assembler called
"WASM". However about the most praiseworthy comment I've heard about it was
something along the lines of "when I wrote everything from scratch and
followed all its rules, WASM seemed to be able to do the job." Basically, I
don't believe WATCOM implemented many of the common, but superfluous
assembler features of MASM or TASM which a lot of people rely on and hence
were complaining about.
The most common problem when trying to link external assembly objects with
C/C++ objects is the name mangling/modification that the C/C++ compiler
does by default. WATCOM C symbols in general are appended with an
undescore ("_"), whereas assembler names are not modified in any way.
This can be changed with a #pragma directive (see Q27, and the online
documentation for changing the symbol renaming convention used by WATCOM
C/C++.) However, Eric Kenslow says that this is unneccesary. WATCOM has
changed the meaning of "cdecl" recently, so how you deal with this may be
different depending on the version of WATCOM C/C++ you are using.
In any event, if you are having problems linking asm and C objects
together, use "wdisasm" (or simply a binary viewer for that matter) and
see how the shared symbol names are being modified for each of your
objects. As recourse, in C you can use the #pragma name modification
directive, and in assembly you can simply append your public/extern names
with underscores as necessary. Modifying your assembly symbol names is
the method Eric Kenslow recommends.
----------------------------------------------------------------------------
Q27. How do #pragma's work? How do I do inline assembly language?
A27. WATCOM's #pragma command is generally used as an alternative way for
defining C/C++ function generation properties. Examples:
1. If you know that the parameters for a function are available either on
the stack or in certain x86 registers then you can assign which go where
*explicitely*.
2. If you know that at link time you will need the exported function
names to be mangled in some nondefault way then you can deal with that in
a #pragma.
3. If you want to generate inline assembly then you can do so as actual
assembly text or opcode bytes. You give a function prototype and then
declare its content using the #pragma aux <function>="<asm>" directive.
This system for dealing with inline assembly is very powerful as it allows
you to explicitely declare your register usage, so that your C and
assembly stitch together perfectly. Surprisingly, Visual C++ and
Borland's "_asm" method is not nearly as powerful. With the "_asm" method
it is recommended that you look at the disassembly (you need to generate a
.COD file in Visual C++) of your surrounding source C to know what
registers are available to use, or simply do not modify any registers at
all. This makes inline assembly coding tedious and difficult to maintain.
In contrast, the WATCOM method requires that you abstract your inline
assembly to have a regular C-function prototype which aids in portability
to non-x86 platforms. A word of warning; inline assembly functions
declared with #pragma aux are not externed and hence behave like regular
C++ "inline" or "static" functions. The typical method of dealing with
multiple C files using the same inline function is to define it in a local
include file common to your C files. In this vein I think of #pragma's as
type checked macros, rather than functions.
Here's an example of the power of #pragma inline assembly for 32 bit FLAT
memory model. Suppose we wish to implement the following:
static void DWORDCopy(long *Source, long *Destination, int Length)
{
for(;Length;Length--)
{
*Source++=*Destination++;
}
}
in tight (i.e., small) assembly. Using the WATCOM disassembly will show
you that the above is *not* compiled to a "rep movsd" no matter what
compiler settings you use. The functionally equivalent inline pragma is
implemented as follows:
void DWORDCopy(long *Source, long *Destination, int Length);
#pragma aux DWORDCopy = " rep movsd " parm [ESI] [EDI] [ECX]\
modify [ESI EDI ECX];
The above function will copy a packed array of 32 bit quantities from a
source pointer to a destination pointer using the "rep movsd" x86 assembly
construct. The source and destination parameters are put into ESI and
EDI, with the length in ECX which is exactly what "rep movsd" requires for
priming. In addition movsd requires that es and ds are set up, but that
is all take care of by the FLAT model start up code. To implement this
same thing for Borland C++ or Visual C++ you need additional priming code
to transfer the source and destination parameters to the correct
registers. Finally, the C-compiler needs to know what registers were
modified by the inline #pragma so that it can figure out what registers
are available to the surrounding C-code. This cuts down on unnecessary
save and restores of registers that is generally required to safely
implement an inline "_asm".
Typically, the meat of the code appears in the double quotes, and is
several lines long, however opcodes can also be entered directly as bytes
as well. Remember that ANSI C constants strings can be broken up in
sequence, and that lines can be stitched together with a "\" at the end.
#pragma's have to be declared on one line, so longer inline assembly
language sequences typically look more like:
void SetMode13(void);
#pragma aux SetMode13 = \
" mov ax,13h " \
" int 10h " \
modify [ax];
(My point above is that this #pragma statement is equivalent to:
#pragma aux SetMode13 = " mov ax,13h int 10h " modify [ax];) You then
call "SetMode13()" as if it were a regular function, and WATCOM does the
inline pasting for you.
Why would you ever want to enter opcodes? Well, intel has a habit of
not documenting all of their mneumonics:
unsigned int RDTSC(void *);
#pragma aux RDTSC = \
0x0f 0x31 /* RDTSC */ \
" mov [esi],eax " \
" mov [esi+4],edx " \
parm [esi] modify [eax edx] value [eax];
(Although the WATCOM C/C++ compiler is actually aware of the rdtsc
instruction, it comes back with a error about the CPU setting when I try
to use it in inline assembly. This is understandable given Intel's
unofficial status of this instruction.)
Direct opcode inlining will become more important as people start using
Intel's "MMX" CPU extensions.
For more examples see "KNUT's WATCOM C/C++ tutorial" at
http://www.oslonett.no/home/oruud/wat_tut.htm
The information given there is not 100% correct, however he gives detailed
examples that should give you a rough idea about how it works. More
detailed information can be found in the online help.
----------------------------------------------------------------------------
Q28. How do I do compiled bitmaps? How do I do on-the-fly generated code?
A28. Its no big deal really. Remember that CS, DS and ES are mapped to the
same physical space. So in principle you need only malloc some space, fill
it with 32 bit instructions (note that the opcodes between 16 and 32 bit do
not translate directly) cast it to a function pointer (be especially careful
with any parameters passed) and call it.
Modifying existing code (realizing of course that you take your life in
your own hands when you do this) is also possible. Cast a function
pointer to a regular data pointer ((char *) is probably the only
appropriate pointer type) modify the data function code as if it were just
an array of opcodes and operands, then call the function.
Unfortunately, it looks like the compiler can do something really odd. If
you assign the address of an existing function to a function pointer and
modify it directly under the same scope, the compiler will tack on a "CS:"
segment override, which will cause a page fault at execution time (Code
selectors cannot be used to write data.) I don't quite see why they did
this but the obvious work around of using another function to modify the
actual code seems to work just fine:
#include <stdio.h>
#include <malloc.h>
#include <stdarg.h>
// printf compatible function prototype
typedef int (* fntype)(char *, ... );
char * fn;
// Assembly language opcode to cause an immediate return:
#define RET 0xc3
void SetReturn(char * ptr)
{
ptr[0] = RET;
}
void main(void)
{
printf("Hello\n"); // Call "printf" as normal
fn = (char *)malloc(128); // Get some memory
SetReturn(fn); // Assign function
((fntype)fn)("Hello\n"); // Call function with parameter
fn = (char *)&printf; // Point to "printf"
SetReturn(fn); // Reassign printf function
printf("Hello\n"); // Call "printf" as normal
}
This was compiled with the -5r and -s switches (only.) Clearly there is
a difference between the stack based and non-stack based libraries which
makes this sort of self-modifying code particularly hazardous to deal
with.
The details for doing compiled bitmaps are beyond the scope of this FAQ,
however the general idea is to construct a number of
mov [edi+offset],immediate
one after the other which plot the sprite. This makes transparency
encoding an intrinsic part of the sprite. However, difficulty with
clipping (especially in the x direction) and destination memory write
alignment makes compiled sprites a questionable compromise to a more
general run length copy routine. For more information read the newsgroup:
rec.games.programmer.
Doing more exotic things like writing your own compiler and setting up
your own compiler environment with protected execution spaces are beyond
the scope of this FAQ, but can probably be dealt with just using DPMI.
Now, before you go off and get any not so bright ideas, read the following
USENET conversation:
> Hi there, I was wondering how you need to set things up so you can modify
> your code and make copies of your functions under DOS4GW/Watcom.... I've
> tried copying the function's code around to several different areas, but
> it always gets a GPF.... Here's a simple example that crashes, if anyone
> has any idea how to make it work, please let me know! Thanks in advance!
>
> void printstuff()
> {
> printf("HELLO\n");
> }
>
> void main()
> {
> void (*pFn)();
>
> pFn = new char[500];
> memcpy( pFn, printstuff, 500 );
> pFn();
> }
The reason this doesn't work is because of the x86's relative addressing
modes. That is to say, that the >> printf("HELLO\n") << statement is
translated to a *relative* call. It gets translated to something like:
mov eax,offset L1 ; Pointer for string "HELLO\n"
call relative ((offset printf)-($+5)) ; $ = current address.
The x86 will automatically add in the current address to the relative
offset and come back with the right address. So in the copied version
of the routine (in pFn()) you won't end up at the address of "printf"
which you desire, because the relative difference was copied, rather
than the physical address.
There is no easy work around for this, and it is for reasons such as
this that self-modifying code and related techniques, such as what
you've tried to do are generally frowned upon. The following two
suggestions which fix the above program also serve to illustrate the
flaw I am pointing out.
(1) Instead of using 500, try using the number 31744 in both places.
(2) Rather than calling printf directly, assign the address of printf
to a global volatile (just to make sure WATCOM doesn't try any
simplification tricks to avoid using it) function pointer, and call
the function pointer instead of printf directly.
----------------------------------------------------------------------------
Q29. How do I install a 32 bit interrupt vector? How do I install a
bimodal interrupt?
A29. Look up _dos_getvect, _dos_setvect, _dos_keep and _chain_intr in the
online help. I don't know much about bimodal interrupts but there is some
sample code in the WATCOM C/C++ general file area which demonstrates it.
The URL is ftp://ftp.powersoft.com/pub/watcom/c_gen/bimodal.zip. I think
the idea is to write some assembly code which can be correctly executed
under either 16 or 32 bit segments and to make sure the interrupt vector
is hooked out without DOS4GW's interrupt code segment translation
intervening.
Here is an example for hooking out the timer interrupt. Note the use of
"volatile" on the Timer_Tick variable declaration. This is an often over
looked detail in this sort of asynchronous kind of programming.
#include <dos.h>
#include <stdio.h>
#include <conio.h>
volatile int Timer_Tick = 0; /* Must be "volatile" */
void __interrupt New_Timer_ISR(void);
void (__interrupt * Old_Timer_ISR)(void);
void __interrupt New_Timer_ISR(void)
{
Timer_Tick ++;
Old_Timer_ISR(); /* Chain back to original interrupt */
}
/* Ordinarily using INT 01Ch is the preferred method, but INT 08h can
* also be used.
*/
#define TIMER_INTERRUPT (0x1C)
void main(void)
{
Old_Timer_ISR = _dos_getvect( TIMER_INTERRUPT );
_dos_setvect( TIMER_INTERRUPT, New_Timer_ISR );
do
{
printf( "%d\n", Timer_Tick );
} while( !kbhit() );
_dos_setvect( TIMER_INTERRUPT, Old_Timer_ISR );
}
If understanding is your goal then keep the following in mind:
- DOS4GW initializes most interrupt vectors to point into the extender
itself. These new vectors are just a translation layer through DPMI to
switch into real mode and call the old vector.
- Since function pointers (including those declared as __interrupt) are
32 bit offsets, the standard old DOS set/get vector int 21h functions will
not work in the standard old way. Using _dos_getvect and _dos_setvect is
really the only reliable way to do ISR management.
- When a new 32 bit ISR is installed, no translation layer is installed
because it is not needed.
- DOS4GW emulates the old real mode interrupts as closely as possible by
preserving the regular register values across the interrupt translation
layer. However, the segment registers are clearly not preserved. This is
not only because a direct Selector->Segment translation makes no sense but
because CS, and SS, must be set up to simulate a 16 bit context.
- DOS4GW implements its own version of int 21h, which looks very much
like a 32 bit extension of int 21h. This is why it is referred to as a
"DOS Extender". In these cases places where there might be Selector->
Segment translation issues, there has been a work around to use the _FLAT
model paradigm. See the online documentation for more information.
- When you are *required* to pass a segment value to a 16 bit interrupt
routine, you need to use the DPMI 300h "Simulated interrupt" function.
Other DOS extenders such as CauseWay and Pmode/w work in similar ways.
----------------------------------------------------------------------------
Q30. How do I get rid of the DOS4GW banner? How do I bind DOS4GW.EXE to
my application? How do I get rid of the external DOS4GW.EXE altogether?
What other DOS extenders can I use?
A30. To get rid of the DOS4GW startup banner, bind your application to
"wstubq.exe" instead of the default "wstub.exe", or altertaively write
your own wstub.exe which does a "set DOS4GW=QUIET".
You cannot simply get rid of DOS4GW.EXE. You need some sort of DOS
extender to drive your 32 bit app. DOS4GW.EXE does not give you a link
option however other extenders such as DOS4G (the professional version of
DOS4GW), CauseWay, and PMODE (available at the x2ftp site) are plug in
DOS4GW compatible DOS extenders that will let you link the extender right
to your code. This way, from the user perspective, your application is no
different from old 16 bit .exe's out there. This is very important for
those interested in making tools that are easily transportable in a stand
alone form.
The other main advantage of using DOS Extenders *other* than DOS4GW, is
that all of them seem to support the DPMI "800" call, which is essential
for mapping physical memory to linear memory so that you can access all of
graphics memory for some SVGA cards directly.
WATCOM's 3rd party support home page includes other DOS extenders that
work with their compiler. Pointers to these can all be found either
directly from a www search engine or on the WATCOM www page. Here's a
quick comparision of what is out there that I am aware of. If you have
information to add or about other extenders (such as blinker, DOS4G)
please tell me so I can include it.
Pharlap/TNT - Large proven API, which supersets DPMI. The extender is
external and a separate link process is required, but WATCOM supports it
as part of the basic compiler environment. I don't know the current going
rate, but last I checked it had a $500 price tag.
PModew/W v1.22 - Small, fast, links to exe, supports exe compression, plug
in compatible with DOS4GW and is free for development stages with a $500
flat charge if supplied with a shipping product. It does not hook out
error exception routines which makes developping with it problematic at
best. People who use it suggest developing with DOS4GW and adding in
pmodew later on. For more information, check out http://www.di.net/pmw/
CauseWay - Fast, extended DPMI API, supports exe compression, links to
final exe, unlimited vitural memory, plug in compatible with DOS4GW, $200.
This is a real no nonsense dos extender which truly supersets DOS4GW
(error handling included, unlike pmodew) and which is at least as robust.
The WATCOM debugger can be used with uncompressed CauseWay extended apps
(be sure to follow the CauseWay installation instructions carefully), but
CauseWay comes with its own debugger that can deal with compressed apps as
well. It comes with an informative manual and plenty of sample code for
assembly and WATCOM C/C++ usage (including examples of using VESA SVGA.)
For more information, check out http://www.devoresoftware.com/
----------------------------------------------------------------------------
Q31. How do I make WATCOM C/C++ work with the latest OS/2 Toolkit?
A31. I know nothing about WATCOM's OS/2 support, however Eric Lekven
(elekven@qualcomm.com) has given me the following information:
WATCOM does not ship its compiler with the newest OS/2 Toolkit and must
be obtained on the IBM OS/2 Developer Connection CDROM or direct from
IBM. Unfortunately both require payment, although there have been
promotional versions of the Developer Connection CDROM shipped with Dr
Dobb's Journal magazine which contain the Toolkit for free. Perhaps
they will do this again when OS/2 Merlin ships.
In order to use IBM's OS/2 Warp Toolkit header files you need to edit
three of the files.
os2def.h:
Find the two identical lines containing
#if defined(__IBMC__) || defined(__IBMCPP__)
Edit these two lines to contain this
#if defined(__IBMC__) || defined(__IBMCPP__) || defined(__WATCOMC__)
mmio.h, mmioos2.h:
Both of these have two lists of #defines, one for country codes,
the other for keyboard codes. The values are decimal. However
these files are non-ANSI in that these decimal numbers have leading
zeroes. Delete the leading zeroes from all these #define
statements.
Breckan Morris has verified this and recommends this over compiling with
the stack interface (/4s or /5s) which would also solve the problem. He
also adds that there is also a line of the form:
#if __IBMC__ || __IBMCPP__
which should be changed to
#if __IBMC__ || __IBMCPP__ || __WATCOMC__
According to Vance Palodichuk, OS/2 4.0 (aka Merlin) has fixed the non-ANSI
leading zeros error from their mmio*.h files, and the modification listed by
Breckan above is sufficient. I.e., you just have to add a "|| __WATCOMC__"
to one line of the os2def.h file to make it work.
It makes me wonder why IBM didn't simply add this modification themselves
just to make it that much easier to use the OS/2 toolkit. This has to be
contrasted with Microsoft and Intel who have clearly gone out of their way
to support WATCOM C/C++. It seems surprising to me that the relationship
between WATCOM and IBM isn't better since they have clearly been beneficial
to each other.
----------------------------------------------------------------------------
Q32. Are there any other WATCOM C/C++ caveats?
A32. Here are some things I've learned while playing with WATCOM C/C++:
1) Structure declarations that include shorts or chars are highly unlikely
to be in the physical order that they are declared. This is because
WATCOM re-orders the entries for efficiency. This is within ANSI C
specifications. ANSI specs do require that the first entry of a structure
always be in the first position. Hence, using structures of structures in
the right way, you can guarrentee the positioning of arbitrary structure
elements.
2) ISR's do not properly load ES. Hence you should insert a #pragma aux
macro (that looks something like: "push ds pop es") if you are using any
library functions. Autoinitialization of arrays or structures is out of
the question, since WATCOM C/C++ uses rep movsd.
3) To mix use of floating point in an ISR and in your main thread you must
save the floating point state (fsave? fstore?) at the beginning of your
ISR and restore it at the end (frestore?). This is because the state of
the FPU cannot be reliably known when the ISR is executed (the stack may
be full because from the main thread). Because saving and restoring the
FPU state is so costly, I would recommend against using the FPU entirely,
within ISRs.
4) DOS4GW ISR's do not share the same stack with your main application.
This means that there are certain function calls that will not work:
longjmp and exit are the ones that immediately come to mind. (Of course
any non-reentrant functions are off limits as well, but those are standard
ISR restrictions.)
5) DOS4GW has no provisions for TSR programming, however it is possible
with the professional version, DOS4G. (I am not aware of these
capabilities in other DOS extenders.)
6) The #pragma aux inline assembly language directive is limited to
assembly sequences of up to 127 bytes or 255 bytes depending on the
version of the compiler. WATCOM recommends using external assembly for
longer assembly sequences. Charlie Wallace makes the good observation
that you can deal with this easily by breaking up your inline fragments
into pieces:
void setup(void);
#pragma aux setup = \
" mov edi,0xa0000 " \
" mov ecx,2000 " \
modify [edi ecx];
void copy(void);
#pragma aux copy = \
" loop1: " \
" mov [edi],0 " \
" inc edi " \
" dec ecx " \
" jnz loop1 " \
modify [edi ecx];
void main(void)
{
setup();
copy();
}
The "modify" statements above are identical (the code generator is smart
enough to see that it doesn't need to restore then save the registers
between setup and copy), but as usual, they must describe the registers
modified in each inline #pragma. If your flow logic is complicated in
such a way that you might jump from one #pragma to another, then you
should include all potentially modified registers for the collection of
#pragma's, in each #pragma's modify clause.
7) Although mentioned elsewhere, I might as well reiterate that WATCOM has
by default implemented "char" as "unsigned char". This can be overidden
with the /j switch, and the IDE does this by default.
8) Apparently the WATCOM C/C++ compiler has difficulty on DOS systems with
64MB of memory. This problem does not occur with Windows DOS boxes. The
solution, according to Charlie Wallace, is to replace w32run.exe (in
either %WATCOM%\binw or %WATCOM%\bin, depending on the which version you
are using) with one of tntrun.exe, d4grun.exe or x32run.exe (i.e., use the
copy command; if things screw up you can always quicky incrementally
reinstall from the CDROM.) Apparently, the one which works is system
dependent.
9) ES is assumed to be equal to DS and the direction flag is assumed
clear. For autoinitialization, structure copying and many library
functions, WATCOM C/C++ simply uses the "rep movsd" assembly instruction
which means that the direction flag must be clear and ES, must be set to
the _FLAT selector, as they are by default.
WATCOM does not allow you to add (E)SP, (E)BP, or segment registers to a
"modify clause" in a #pragma. So if they are modified (by a BIOS call, or
by some inline assembly) you have to save and restore those registers
yourself. Similarly the direction flag should be explicitely cleared with
the "cld" instruction if it is modified.
----------------------------------------------------------------------------
Q33. Will WATCOM C/C++ support MMX?
A33. Yes. Intel made the following announcement in March 1996:
"Powersoft Corporation has announced a commitment to deliver a version
of Watcom C/C++ that supports Intel's new MMX(tm) technology. This
support will enable development of lightning fast applications that
exploit the capabilities of the MMX instruction set and that leverage
the industry-leading optimization technology of Watcom C/C++. Watcom
C/C++ will feature complete debugging support (including MMX technology
register display and the disassembly of MMX instructions) as well as a
functional interface from C/C++ that generates inline MMX instructions."
----------------------------------------------------------------------------
Q34. So what is your story? Why did you do this?
A34. I was a summer hire for WATCOM many eons ago, and I appreciate that
they gave me my first real job. I have always been impressed by their
compilers and I've always wanted to see them crush both Borland and
Microsoft in the compiler arena. (It looks like Borland will be laying
down for the count, but Microsoft is still there of course.)
WATCOM's most notable weakness is user support. Their documentation is
very dry and generally does not fully explain all of the compiler's
capabilities. I'm told this is the main reason a very high profile game
company stopped using their compiler in favour of another 32 bit DOS based
C compiler. I've also found that lately, I'd been posting on a daily
basis just answering people's basic questions about WATCOM C/C++. It is
in the hopes of curing this problem that I've written up this FAQ.
Finally, I am hoping that people make contributions and possibly submit
corrections so that I can verify my own knowledge. This process also
results in a more reliable FAQ. Numerous contributions have been made
thus far (including one from a WATCOM employee, and one from an Intel
employee representing Intel), and I have received a lot of positive
feedback which has made it worth while.
----------------------------------------------------------------------------
Cool contributions
~~~~~~~~~~~~~~~~~~
C01. Profiling and debugging all rolled into one using an external
terminal connected by serial. Contributed by Charlie Wallace.
[PH - The following contribution describes an alternative method for
profiling and debugging using a serial port connection to another
machine. I believe the idea is to redefine default the epilogue and
prologue code for your functions to communicate with a debugging or
profiling device. The details were too complicated for me to verify.
However, for advanced WATCOM C/C++ users looking for an alternative
debugging or profiling method, the following may be useful.]
This is a small tip on using /ee /ep /en options of watcom, usually
these are used by the watcom profiler. I`ve found them useful for
debugging in the past, especially when you can`t load into the
debugger, like when watcom debugger had no support for X32,
what i`d do was compile with those options which adds a call
before and after every function call, so when the code locked
up i knew roughly where it was happening, i made the __PRO
routine emit the function name to the serial port at a
preset speed to a terminal, with a tab added at every level
entered, then the __EPI routine removed a tab and a new line
so on the serial terminal it looked thus :
main(i)
my_func1(i)
my_func2(i)
my_func2(o)
my_func1(o)
main(o)
where (i) and (o) are in and out, when the code locked up
only the last call entered would be displayed.
there are many other uses of this function, profiling with
other hardware, remember though this changes the execution
flow, you can compensate for it though, making a simple
debugger, debug options, watchdogs for memory leak and
code overwrites and so on . . .
However one caveat is to make sure you don`t add profile
hooks to the profiler code, write it in asm in a seperate
asm file, (don`t use #pragma aux), and don`t call
a C function of your own that has been compiled with /ep /en,
otherwise it`ll recurse.
a small example of how it works, assuming a simple compile
with wcl386 /ep /ee /en test.c pro.asm
where test.c is something like , simple..
int foo(int a)
{
return a-1;
}
main()
{
int a;
a=foo(1);
}
which is compiled to
db 'foo'
db 3
_foo:
push ebp
mov ebp,esi
call __PRO
; does the function
call _EPI
pop ebp
ret
db 'main'
db 4
_main:
push ebp
mov ebp,esi
call __PRO
; code goes here..
call _EPI
pop ebp
ret
so get the function name, get the return address, esp will point to
it, subtract the length of the code before the __PRO call, ie the
push ebp + mov ebp,esi and add 1, use wdisasm to calculate this,
usually its 9, but i`m not saying it always will be, so check.
this byte is the length of the function name, subtract this from
the previous address just calculated and this gives you the
function name + length, ready to print out, or do whatever you
like..
Here is a 32bit version of __PRO and __EPI, for 32bit flat mode.
pro.asm - snip here 8-X
;
; use this fragment to code your own routines.
;
.586p
.model flat
.code
PUBLIC __PRO
PUBLIC __EPI
; this routine gets called first
;
; usually like this, *- means subtract from current offset
;
;function_name:
; db 'my_c_function'
; db *-function_name (compute length of prev string)
;my_c_function:
; push ebp
; mov ebp,esp
; call __PRO
;
;
__PRO proc near
push esi
push eax
mov esi,[esp]
sub esi,9 ; this is the length of the
; call __PRO+mov ebp,esp+push ebp+1
; it may need to be changed to match different
; compile options. check with wdisasm
xor eax,eax
mov byte ptr al,[esi] ; length of function name
sub esi,eax
; esi -> function name
; eax -> length of string
; do what you will with these, EXCEPT ! call any function in C
; that you compiled with /ep or /en, otherwise it`ll recurse
; for ever (at least for a while anyway).
pop eax
pop esi
ret
__PRO endp
; this gets called at the end of the function
; usually like this :-
;
; call __EPI
; pop ebp
; ret
__EPI proc near
; do what you will here, just save all the reg's
ret
__EPI endp
end
pro.asm - snip here 8-X
----------------------------------------------------------------------------
C02. Convert WATCOM's help file format to a text file for easier
reading and potentially for easier manipulation.
Joergen Bech sent me a program which will convert WATCOM's .IHP files to
a text file, a table of contents file and an index file. This will allow
you to peruse the file from your favourite text editor, or manipulate it
as you see fit. The program is freely available at:
http://www.geocities.com/SiliconValley/9498/ihp_conv.zip
It assumes you have DOS4GW.EXE at your disposal, in your path.
----------------------------------------------------------------------------
Thanks for the feedback!
========================
I have received numerous emails in response to my creation and public
dissemination of the WATCOM C/C++ FAQ. They have, for the most part, been
very encouraging. The contributions and corrections that have been sent
to me have served to increase the quality of the FAQ tremendously.
Readers can rest assure knowing that the accuracy and content is being
examined very carefully by discerning WATCOM C/C++ users.
I would like to especially thank WATCOM Systems and Intel corp. for their
invaluable individual